package com.security.demo.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;

/**
 * @author H
 * @date 2023/1/11
 */
@Component
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private DataSource dataSource;
    @Autowired
    private UserDetailsService userDetailsService;

    // 代码 1 内存验证
    // @Override
    // protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    //     // 密码编码器
    //     BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    //     // 使用内存存储
    //     auth.inMemoryAuthentication()
    //             // 设置密码编码器
    //             .passwordEncoder(passwordEncoder)
    //             // 注册用户admin，密码abc，并赋予USER 和 ADMIN的角色权限
    //             .withUser("admin")
    //             .password("$2a$10$nL/7GKdMBesncG20U9kAW.fE11PO5uOkgQUjMHGXZs1KKiD3YRtCO")
    //             .roles("USER", "ADMIN")
    //             // 连接方法
    //             .and()
    //             // 用户名 myuser， 密码123456
    //             .withUser("myuser")
    //             .password("$2a$10$r9pfQ975ljIIH6Kw5i.rdeOfCSA2A.Zl6Snq0fwFFy8LHFyH4qJKa")
    //             .roles("USER");
    // }

    // 代码 2 内存验证
    // @Override
    // protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    //     // 密码编码器
    //     BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    //     // 使用内存存储
    //     InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> userConfig = auth.inMemoryAuthentication()
    //             // 设置密码编码器
    //             .passwordEncoder(passwordEncoder);
    //     // 注册用户admin，密码abc，并赋予USER 和 ADMIN的角色权限
    //     userConfig.withUser("admin")
    //             .password("$2a$10$nL/7GKdMBesncG20U9kAW.fE11PO5uOkgQUjMHGXZs1KKiD3YRtCO")
    //             .authorities("ROLE_USER", "ROLE_ADMIN");
    //
    //     // 用户名 myuser， 密码123456
    //     userConfig.withUser("myuser")
    //             .password("$2a$10$r9pfQ975ljIIH6Kw5i.rdeOfCSA2A.Zl6Snq0fwFFy8LHFyH4qJKa")
    //             .authorities("ROLE_USER");
    // }

    // 使用用户名称查询密码
    // String pwdQuery = "SELECT user_name, pwd, avaliable FROM t_user WHERE user_name = ?";
    // // 使用用户名称查询角色信息
    // String roleQuery = "SELECT u.user_name, r.role_name FROM t_user u, t_user_role ur, t_role r WHERE u.id = ur.user_id AND r.id = ur.role_id AND u.user_name = ?";

    // @Override
    // protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    //     // 密码编码器
    //     BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    //     auth.jdbcAuthentication()
    //             // 密码编码器
    //             .passwordEncoder(passwordEncoder)
    //             // 数据源
    //             .dataSource(dataSource)
    //             // 查询用户，自动判断密码是否一致
    //             .usersByUsernameQuery(pwdQuery)
    //             // 赋予权限
    //             .authoritiesByUsernameQuery(roleQuery);
    // }

    // 加密密钥
    String secret = "uvwxyz";

    // @Override
    // protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    //     // 密码编码器
    //     PasswordEncoder passwordEncoder = new Pbkdf2PasswordEncoder(secret);
    //     auth.jdbcAuthentication()
    //             // 密码编码器
    //             .passwordEncoder(passwordEncoder)
    //             // 数据源
    //             .dataSource(dataSource)
    //             // 查询用户，自动判断密码是否一致
    //             .usersByUsernameQuery(pwdQuery)
    //             // 赋予权限
    //             .authoritiesByUsernameQuery(roleQuery);
    // }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 密码编码器
        PasswordEncoder passwordEncoder = new Pbkdf2PasswordEncoder(secret);
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder);
    }

    // @Override
    // protected void configure(HttpSecurity http) throws Exception {
    //     // 限定签名后的权限
    //     http.authorizeRequests()
    //             // 限定"/user/welcome"请求赋予角色ROLE_USER或者ROLE_ADMIN
    //             .antMatchers("user/welcome", "/user/details").hasAnyRole("USER", "ADMIN")
    //             // 限定"/admin/"下所有请求权限赋予角色ROLE_ADMIN
    //             .antMatchers("/admin/**").hasAuthority("ROLE_ADMIN")
    //             // 其它路径允许签名后访问
    //             .anyRequest()
    //             // 表示没有配置过权限限定的路径允许全部访问
    //             .permitAll()
    //
    //             // and代表连接词，并取消之前限定前提规则
    //             .and()
    //             // 对于没有配置权限的其它请求允许匿名访问
    //             .anonymous()
    //
    //             .and()
    //             // 使用Spring Security默认的登录页面
    //             .formLogin()
    //
    //             .and()
    //             // 启用Http basic请求输入用户和密码
    //             .httpBasic();
    // }

    // @Override
    // protected void configure(HttpSecurity http) throws Exception {
    //     // 限定签名后的权限
    //     http.authorizeRequests()
    //             // 使用Spring表达式限定只有角色ROLE_USER 或者 ROLE_ADMIN
    //             .antMatchers("/user/**").access("hasRole('USER') or hasRole('ADMIN')")
    //             // 设置访问权限给角色ROLE_ADMIN，要求是完整登录（非记住我登录）
    //             .antMatchers("/admin/welcome1").access("hasAuthoity('ROLE_ADMIN') && isFullyAuthenticated()")
    //             // 限定"/admin/welcome2"访问权限给角色ROLE_AMDIN，允许不完整登录
    //             .antMatchers("/admin/welcome2").access("hasAuthority('ROLE_ADMIN')")
    //
    //             // 使用记住我功能
    //             .and().rememberMe()
    //
    //             .and()
    //             // 使用Spring Security默认的登录页面
    //             .formLogin()
    //
    //             .and()
    //             // 启用Http basic请求输入用户和密码
    //             .httpBasic();
    // }

    // @Override
    // protected void configure(HttpSecurity http) throws Exception {
    //     http
    //             // 使用安全渠道，限定为https请求
    //             .requiresChannel().antMatchers("/admin/**").requiresSecure()
    //             // 不适用https请求
    //             .and().requiresChannel().antMatchers("/user/**").requiresInsecure()
    //             // 限定允许访问的角色
    //             .and()
    //             .authorizeRequests()
    //             .antMatchers("/admin/**").hasAnyRole("ADMIN")
    //             .antMatchers("/user/**").hasAnyRole("ROLE", "ADMIN");
    // }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http
               // 访问/admin下的请求需要管理员权限
               .authorizeRequests()
               .antMatchers("/admin/**").access("hasRole('ADMIN')")
               .antMatchers("/security/**").access("hasRole('ADMIN')")
               // 启用记住我功能
               .and()
               .rememberMe().tokenValiditySeconds(86400).key("remember-me-key")

               // 启用http basic功能，realmName：作用是设置模态对话框的标题
               .and().httpBasic().realmName("my-basic-name")

               // 通过签名后可以访问任何请求
               .and().authorizeRequests().antMatchers("/**").permitAll()
               // 设置登录页和默认的跳转路径
               .and()
               .formLogin()
               .loginPage("/login/page")
               .defaultSuccessUrl("/admin/wel")

               // 登出页面和默认跳转路径
               .and()
               .logout()
               .logoutUrl("/logout/page") // 在WebMvcConfig.java中配置的有路径对应的视图映射
               .logoutSuccessUrl("/welcome");
    }

    public static void main(String[] args) {
        // BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        PasswordEncoder passwordEncoder = new Pbkdf2PasswordEncoder("uvwxyz");
        System.out.println(passwordEncoder.encode("123456"));
    }
}
